#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import json
import random
import time
from collections import OrderedDict

global s_dicAINameUsed
s_dicAINameUsed = {}
global s_rgAINames
s_rgAINames = ["AI1", "AI2", "AI3", "AI4", "AI5", "AI6", "AI7", "AI8", "AI9", "AI10", "AI11", "AI12", "AI13", "AI14", "AI15"]

KEY_PLAYER_NAME = "playerName"
KEY_MESSAGE_TYPE = "messageType"
KEY_CARDS_GROUP = "cardsGroup"
KEY_PLAYER_CARDS = "playerCards"
KEY_ACTION_TYPE = "actionType"
KEY_ACTION_TYPE_SEND_A_CARD = "sendACard"
KEY_ACTION_TYPE_TAKE_A_GROUDP = "takeAGroup"
KEY_PLAYER_INDEX = "playerIndex"
KEY_SEND_CARD = "cardSend"
KEY_TAKE_GROUP = "groupTake"
KEY_IS_AI = "isAI"
KEY_IS_TEMP = "isTemp"
KEY_ROUND_INDEX = "roundIndex"

CARDS_COUNT_SUM = 104
CARD_GROUP_COUNT = 4
GROUP_CARD_MAX = 5
ICONS_COUNT = 15

class MessageType:
    MESSAGE_GAME_START = "game_start"
    MESSAGE_GAME_PLAY = "game_play"
    MESSAGE_GAME_END = "game_end"
    MESSAGE_GOTO_HALL = "goto_hall"
    MESSAGE_ERROR = "error"

class ActionType:
    ACTION_TYPE_SEND_A_CARD = "sendACard"
    ACTION_TYPE_TAKE_A_GROUP = "takeAGroup"

class AIManage:
    def __init__(self, roomManager):
        self.m_bIsAI = True
        self.m_bIsTemp = False
        self.m_roomManager = roomManager
        self.m_nRoomID = -1
        self.m_opponents = []
        self.m_gameManage = False
        self.m_nPlayerCount = 0
        self.m_nPlayerStarScore = 100
        self.m_nPlayerIndex = -1
        self.m_rgCards = []
        self.m_rgPublicCardsGroup = []
        self.m_bHasSendCard = False
        self.m_bHasTakeGroup = False
        self.m_rgSendCards = []
        self.m_dicSendCards = {}
        self.m_nTakingGroupCard = 0
        self.m_rgSendCardMessage = []
        self.m_bCardsOperating = False
        self.m_rgTakeGroupMessage = []
        self.m_bWattingTakeGroup = False
        self.m_nCurrentRound = 1
        # random AI Name
        nameIndex = random.randint(0, len(s_rgAINames) - 1)
        if len(s_dicAINameUsed) < len(s_rgAINames):
            i = 0
            while i < 1000 and s_dicAINameUsed.has_key(nameIndex):
                i += 1
                nameIndex = random.randint(0, len(s_rgAINames) - 1)
        if s_dicAINameUsed.has_key(nameIndex):
            s_dicAINameUsed[nameIndex] += 1
        else:
            s_dicAINameUsed[nameIndex] = 0
        self.m_strPlayerName = s_rgAINames[nameIndex]
        self.m_nPlayerIcon = nameIndex % ICONS_COUNT

    def setGameInfo(self, nRoomID, nIndex):
        self.m_nRoomID = nRoomID
        self.m_nPlayerIndex = nIndex

    def resetOpponent(self, players):
        try:
            self.m_opponents = []
            for player in players:
                if (player is self) == False:
                    self.m_opponents.append(player)
            self.m_nPlayerCount = len(players)
        except Exception, e:
            print "error:", e

    def startGame(self, players, gameManage, startMessage):
        try:
            self.m_opponents = []
            for player in players:
                if (player is self) == False:
                    self.m_opponents.append(player)
            self.m_gameManage = gameManage
            strTestMessage = startMessage
            self.m_nCurrentRound = 1
            self.getMessage(strTestMessage)
        except Exception, e:
            print "error:", e

    def midwayStartGame(self, gameManage):
        try:
            print "Midway Player join"
            
            self.m_bIsTemp = True
            self.m_gameManage = gameManage
            self.m_rgCards = []
            rgCards = gameManage.getPlayerLeftCards(self.m_nPlayerIndex)
            for card in rgCards:
                self.m_rgCards.append(card)
            self.m_rgCards.reverse()
            self.m_nCurrentRound = gameManage.m_nRoundIndex
            self.m_rgPublicCardsGroup = []
            rgPublicCardsGroup = gameManage.m_rgPublicCardsGroup
            for group in rgPublicCardsGroup:
                g = []
                for card in group:
                    g.append(card)
                self.m_rgPublicCardsGroup.append(g)
            
            rgReadyPlayerCard = gameManage.m_rgReadyPlayerCard
            print "gameManage.m_rgReadyPlayerCard : ", rgReadyPlayerCard
            
            bSendedThisRound = False
            for dic in rgReadyPlayerCard:
                if dic['playerIndex'] == self.m_nPlayerIndex:
                    bSendedThisRound = True
                self.m_dicSendCards[dic['cardSend']] = dic['playerIndex']
                self.m_rgSendCards.append(dic['cardSend'])
        
            dicWaitingInfo = gameManage.m_dicWaitingInfo
        
            if len(dicWaitingInfo) > 0:
                nWaitingPlayer = dicWaitingInfo["playerIndex"]
                self.m_bWattingTakeGroup = True;
                self.m_nTakingGroupCard = dicWaitingInfo["cardSend"]
                if nWaitingPlayer == self.m_nPlayerIndex:
                    self.m_nCurrentRound -= 1
                    self.takeGroup()

            elif bSendedThisRound == False:
                self.sendCard()
    
        except Exception, e:
            print "error:", e

    def breakConnectionWithOpponent(self):
        self.m_opponents = []
        self.m_nRoomID = 0
        self.m_opponents = []
        self.m_gameManage = False
        self.m_nPlayerCount = 0
        self.m_nPlayerStarScore = 100
        self.m_nPlayerIndex = -1
        self.m_rgCards = []
        self.m_rgPublicCardsGroup = []
        self.m_bHasSendCard = False
        self.m_bHasTakeGroup = False
        self.m_rgSendCards = []
        self.m_dicSendCards = {}
        self.m_nTakingGroupCard = 0
        self.m_rgSendCardMessage = []
        self.m_bCardsOperating = False
        self.m_rgTakeGroupMessage = []
        self.m_bWattingTakeGroup = False
        self.m_nCurrentRound = 1

    def getMessage(self, gameMessage):
        try:
            dicJsonMessage = json.loads(gameMessage)
            messageType = dicJsonMessage[KEY_MESSAGE_TYPE]
            if messageType == MessageType.MESSAGE_GAME_START:
                self.m_rgPublicCardsGroup = dicJsonMessage[KEY_CARDS_GROUP]
                self.m_rgCards = dicJsonMessage[KEY_PLAYER_CARDS][self.m_nPlayerIndex]
                self.m_rgCards.reverse()
                self.m_nPlayerCount = len(dicJsonMessage[KEY_PLAYER_CARDS])
#                print "Public Cards Group : ", self.m_rgPublicCardsGroup
#                print "My Cards : ", self.m_rgCards
#                print "Player Count : ", self.m_nPlayerCount
                self.sendCard()
                self.m_bHasSendCard = True
            elif messageType == MessageType.MESSAGE_GAME_PLAY:
                actionType = dicJsonMessage[KEY_ACTION_TYPE]
                if actionType == ActionType.ACTION_TYPE_SEND_A_CARD:
                    nRoundIndex = dicJsonMessage[KEY_ROUND_INDEX]
                    if self.m_bCardsOperating == False and nRoundIndex == self.m_nCurrentRound:
                        self.parseSendCardMessage(dicJsonMessage)
                    else:
#                        print "Player%d is CardsOperating :" % self.m_nPlayerIndex, self.m_bCardsOperating
#                        print "Player%d append a sendCard Message :" % self.m_nPlayerIndex , gameMessage
                        self.m_rgSendCardMessage.append(dicJsonMessage)
                elif actionType == ActionType.ACTION_TYPE_TAKE_A_GROUP:
                    if self.m_bWattingTakeGroup == True:
                        self.parseTakeGroupMessage(dicJsonMessage)
                    else:
                        self.m_rgTakeGroupMessage.append(dicJsonMessage)
                else:
                    raise Exception("cannot use actionType : ", actionType)
    
        except Exception,e:
            print "error:", e


    def sendGameMessage(self, gameMessage):
        self.getMessage(gameMessage)

    def sendCard(self):
        if len(self.m_rgCards) == 0:
            self.m_roomManager.playerLeftRoom(self, self.m_nRoomID)
            return False
        else:
            return True

    def sendCardMessageToOpponents(self, message):
        strJsonMessage = json.dumps(message)
        strGameMessage = self.m_gameManage.receiveAMessage(strJsonMessage)
        for opponent in self.m_opponents:
            opponent.sendGameMessage(strGameMessage)
        if len(self.m_rgSendCards) == self.m_nPlayerCount:
            self.sendCardsToCardGroup()

    def takeGroup(self):
        pass

    def parseSendCardMessage(self, dicJsonMessage):
        try:
            card = dicJsonMessage[KEY_SEND_CARD]
            nPlayerIndex = dicJsonMessage[KEY_PLAYER_INDEX]
            self.m_dicSendCards[card] = nPlayerIndex
            self.m_rgSendCards.append(card)
        
#            print "Player%d Get Send Card Message From Player %d" % (self.m_nPlayerIndex, nPlayerIndex)
#            print "Player%d Current m_rgSendCards len : " % self.m_nPlayerIndex , len(self.m_rgSendCards)

            if len(self.m_rgSendCards) == self.m_nPlayerCount:
                self.sendCardsToCardGroup()
        
        except Exception,e:
            print "error:", e

    def parseTakeGroupMessage(self, dicJsonMessage):
        try:
            group = dicJsonMessage[KEY_TAKE_GROUP]
            nIndex = dicJsonMessage[KEY_PLAYER_INDEX]
            nCard = self.m_nTakingGroupCard
        
            self.m_nTakingGroupCard = 0
        
            self.m_rgPublicCardsGroup[group] = []
            self.m_rgPublicCardsGroup[group].append(nCard)
        
            self.sendCardsToCardGroup()
        except Exception,e:
            print "error:", e

    def sendCardsToCardGroup(self):
        try:
            self.m_bCardsOperating = True
            
            self.m_rgSendCards.sort()
            rgGroupsHeads = []
            for group in self.m_rgPublicCardsGroup:
                rgGroupsHeads.append(group[len(group) - 1])
            rgGroupsHeads.sort()
            nSmallestGroupHead = rgGroupsHeads[0]
            
            while 0 < len(self.m_rgSendCards):
                actionCard = self.m_rgSendCards[0]
                actionPlayerIndex = self.m_dicSendCards[actionCard]
                
                #case 1  card is smallest of all group head
                if actionCard < nSmallestGroupHead:
                    self.m_nTakingGroupCard = actionCard
                    del self.m_rgSendCards[0]
                    
                    self.m_bWattingTakeGroup = True;
#                    print "Player%d Take Group action from Player : %d" % (self.m_nPlayerIndex, actionPlayerIndex)
                    if actionPlayerIndex == self.m_nPlayerIndex:
                        self.takeGroup()
                    elif len(self.m_rgTakeGroupMessage) > 0:
                        self.parseTakeGroupMessage(self.m_rgTakeGroupMessage.pop())
                    
#                    print "Player%d Current m_rgSendCards :" % self.m_nPlayerIndex , self.m_rgSendCards
                    return
    
                #case 2  card isn't smallest, find the right group (the biggest one of all the group'heads smaller than the actionCard)
                else:
                    nGroupIndex = -1
                    nBiggestSmallerGroupHead = 0
                    i = 0
                    
                    self.m_bWattingTakeGroup = False;
                    while i < 4:
                        group = self.m_rgPublicCardsGroup[i]
                        groupHead = group[len(group) - 1]
#                        print "group : ", group
#                        print "groupHead : ", groupHead
                        if groupHead < actionCard and groupHead > nBiggestSmallerGroupHead:
                            nBiggestSmallerGroupHead = groupHead
                            nGroupIndex = i
                        i += 1
                    
                    if nGroupIndex < 0 or nBiggestSmallerGroupHead <= 0 :
                        raise Exception("Player%d not find the right group" % self.m_nPlayerIndex)
                    else:
                        if len(self.m_rgPublicCardsGroup[nGroupIndex]) < GROUP_CARD_MAX:
                            self.m_rgPublicCardsGroup[nGroupIndex].append(actionCard)
                        else:
                            self.m_rgPublicCardsGroup[nGroupIndex] = []
                            self.m_rgPublicCardsGroup[nGroupIndex].append(actionCard)
                            del self.m_dicSendCards[actionCard]
        
                    del self.m_rgSendCards[0]

#                print "Player%d Current m_rgSendCards :" % self.m_nPlayerIndex , self.m_rgSendCards

            if len(self.m_rgSendCards) == 0 :
                self.m_bWattingTakeGroup = False
                self.m_bCardsOperating = False
                self.sendCard()
                self.m_nCurrentRound += 1
                print "Player%d current round : %d" % (self.m_nPlayerIndex, self.m_nCurrentRound)

                for dicJsonMessage in self.m_rgSendCardMessage :
                    if dicJsonMessage[KEY_ROUND_INDEX] == self.m_nCurrentRound:
                        self.parseSendCardMessage(dicJsonMessage)

        except Exception,e:
            print "error:", e

class SimpleAI(AIManage):
    def sendCard(self):
        try:
            if (AIManage.sendCard(self) == False) : return
            
            card = self.m_rgCards.pop()
            self.m_rgSendCards.append(card)
            self.m_dicSendCards[card] = self.m_nPlayerIndex
            message = OrderedDict()
            message[KEY_MESSAGE_TYPE] = MessageType.MESSAGE_GAME_PLAY
            message[KEY_ACTION_TYPE] = ActionType.ACTION_TYPE_SEND_A_CARD
            message[KEY_PLAYER_INDEX] = self.m_nPlayerIndex
            message[KEY_SEND_CARD] = card
            message[KEY_IS_AI] = True
            message[KEY_IS_TEMP] = self.m_bIsTemp
            
#            print "Player%d send Card %d" % (self.m_nPlayerIndex, card)
            AIManage.sendCardMessageToOpponents(self, message)
        
        except Exception,e:
            print "error:", e

    def takeGroup(self):
        try:
            nGroup = random.randint(0, CARD_GROUP_COUNT -1)
            
            message = OrderedDict()
            message[KEY_MESSAGE_TYPE] = MessageType.MESSAGE_GAME_PLAY
            message[KEY_ACTION_TYPE] = ActionType.ACTION_TYPE_TAKE_A_GROUP
            message[KEY_PLAYER_INDEX] = self.m_nPlayerIndex
            message[KEY_TAKE_GROUP] = nGroup
            message[KEY_IS_AI] = True
            
            strJsonMessage = json.dumps(message)
            strGameMessage = self.m_gameManage.receiveAMessage(strJsonMessage)
            for opponent in self.m_opponents:
                opponent.sendGameMessage(strGameMessage)
    
            self.getMessage(strGameMessage)
        except Exception,e:
            print "error:", e
